package design.patterns.behavioral;

/**
 * -----
 * 命令行模式
 * 解释：
 * 命令模式是一种行为设计模式，
 * 它可将请求转换为一个包含与请求相关的所有信息的独立对象。
 * 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中， 且能实现可撤销操作。
 * <p>
 * 预备知识
 * 命令行模式，是指层与层之间分离，但是使用绑定的方式进行连接
 * 数据结构：栈
 * -----
 */

import java.util.Stack;
/**
 * 情景
 * 在word中可以进行回撤操作
 *
 * 例子进行了大量简化，仅使用字符串进行表示。
 * 按钮的功能有插入(InsertTxtCommand)、删除(DeleteTxtCommand)
 */
public class B_Command {
    public static void main(String[] args) {
        /* 创建字符串 */
        StringBuilder stringBuilder = new StringBuilder();

        CommandHistory commandHistory = new CommandHistory();

        InsertTxtCommand insertTxtCommand = new InsertTxtCommand(stringBuilder, "12");
        Button insertTxtButton = new Button();
        insertTxtButton.bindCommand(insertTxtCommand);
        insertTxtButton.click();
        System.out.println(stringBuilder.toString());

        DeleteTxtCommand deleteTxtCommand = new DeleteTxtCommand(stringBuilder);
        Button deleteButton = new Button();
        deleteButton.bindCommand(deleteTxtCommand);
        deleteButton.click();
        System.out.println(stringBuilder.toString());

        System.out.println(Command.commandHistory);

    }

}

/**
 * 代码中主要有三个类
 * Command 命令的抽象类
 * InsertString继承Command 插入字符的类
 * CommandHistory 记录的历史类
 *
 */
abstract class Command {
    public static CommandHistory commandHistory = new CommandHistory();
    void run(){
        this.execute();
        commandHistory.push(this);
    }
    abstract void execute();


}

/**
 * 插入类，主要记录插入的字符串
 */
class InsertTxtCommand extends Command{
    private StringBuilder str;
    private String insertTxt;

    public InsertTxtCommand(StringBuilder str, String inserTxt) {
        this.str = str;
        this.insertTxt = inserTxt;
    }

    @Override
    public void execute() {
        str.append(insertTxt);
    }

    public void setInsertTxt(String insertTxt) {
        this.insertTxt = insertTxt;
    }

    @Override
    public String toString() {
        return "InsertTxtCommand{" +
                "insertTxt='" + insertTxt + '\'' +
                '}';
    }
}

class DeleteTxtCommand extends Command{
    private StringBuilder str;
    public DeleteTxtCommand(StringBuilder str){
        this.str = str;
    }

    @Override
    public void execute() {
        int lastIndex = str.length()-1;
        str.delete(lastIndex,lastIndex+1);
    }

    @Override
    public String toString() {
        return "DeleteTxtCommand";
    }
}
/**
 * 记录历史的类，主要记录执行Command的历史记录。
 */
class CommandHistory {
    private Stack<Command> history = new Stack<>();

    public void push(Command c) {
        history.push(c);
    }

    public Command pop() {
        if (isEmpty()){
           throw new RuntimeException("无法进行撤销");
        }
        return history.pop();
    }

    public boolean isEmpty() { return history.isEmpty(); }

    @Override
    public String toString() {
        return "CommandHistory{" +
                "history=" + history +
                '}';
    }
}

class Button{
    private Command command;
    public void bindCommand(Command command){
        this.command = command;
    }
    public void click(){
        command.run();
    }
}